package com.touch.jgloo.core;
import java.util.*;
import javax.media.opengl.*;
import com.sun.opengl.util.texture.*;
import com.touch.graphics.UV;
import com.touch.graphics.Renderable;
import com.touch.jgloo.JGLTextureLoader;
/**
 * The most basic JGLObject Object.
 * This handles and draws the Object using OpenGL (JOGL)
 * @author Homicidal Monkey
 * @Version 10.1.9
 * @since r419
 * @see com/touch/Licence
 */
public class JGLObject extends JGLBase implements Renderable, JGLCompilable, Cloneable
{
	//defines what form of AlphaBlending will be used.
	private boolean additiveBlend = true;
	//the polygon object that is used
	private Vector <JGLPolygon> polygons = new Vector <JGLPolygon> ();
	//the index of the GLList. Used for compiling the object
	private int glListIndex = JGLConstants.NULL_LIST;
	//only called when first called. 
	private boolean firstCall = true;

	/**
	 * Renders the JGLObject by drawing it to the screen.
	 * @since r461
	 */
	public void render()
	{
		checkForLists();
		//scroll through each polygon
		for(int i = 0; i < this.polygons.size(); i++)
		{
			final JGLPolygon polygon = polygons.elementAt(i);
			//if the polygon exists
			if(polygon != null)
			{				
				if(polygon.renderState != GL.GL_NONE && polygon.drawStart)		
				{					
					initiateRender();			
					//confirm that the texture exists					
					renderTexture(polygon);
					//gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
					GL_INSTANCE.glBegin(polygon.renderState);
				}
					//draw the polygon
					polygon.render();	
					
				if(polygon.renderState != GL.GL_NONE && polygon.drawEnd)
				{
					GL_INSTANCE.glEnd();
					//gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE,GL.GL_MODULATE);
					//GL_INSTANCE.glDisable(GL.GL_BLEND);
					//GL_INSTANCE.glDisable(GL.GL_ALPHA_TEST);
				}
			}
		}

	}
	/**
	 * Destroys the compiled JGLObject.
	 * @since r461
	 */
	public synchronized void clean() 
	{
		//confirm that the compiled object exists
		if(this.glListIndex != JGLConstants.NULL_LIST)
			GL_INSTANCE.glDeleteLists(this.glListIndex, 1);	
	}
	/**
	 * Compiles the JGLObject
	 * @since r461
	 */
	public synchronized void compile()
	{
		cleanLists();
		//generate a new list for this object
		this.glListIndex = GL_INSTANCE.glGenLists(1);
		//start the glList and compile it
		GL_INSTANCE.glNewList(this.glListIndex, GL.GL_COMPILE);
		{
			//run all of the commands that the glList calls.
			this.render();
		}
		//end the glList
		GL_INSTANCE.glEndList();
		//tell the renderer to use glLists instead of rendering the actual commands
		firstCall = false;		
	}	
	/**
	 * Adds a polygon to the JGLObject
	 * @param polygon Polygon to add
	 * @since r461
	 */
	public synchronized void addPolygon(final JGLPolygon polygon)
	{
		this.polygons.add(polygon);
	}
	/**
	 * Gets the polygon specified at a specific point. 
	 * That polygon must exist.
	 * @param pIndex Index of the polygon
	 * @return Returns the polygon at the index point
	 * @since r461
	 */
	public synchronized JGLPolygon getPolygon(final int pIndex)
	{             
		//return the polygon at the index
		return this.polygons.elementAt(pIndex);
	}
	public synchronized void setPolygon(final int pIndex, final JGLPolygon polygon)
	{
		this.polygons.set(pIndex, polygon);
	}
	/**
	 * Sets the texture of the polygon
	 * @param index Index of the polygon
	 * @param texture Texture to use
	 * @since r461
	 */
	public void setTexture(final int index, final Texture texture)
	{
		//set the texture of the polygon at the specified point
		this.polygons.elementAt(index).texture = texture;
	}
	/**
	 * Sets the UV of the Object by defining the points.
	 * @param polygonIndex index of the polygon
	 * @param point Index of the point
	 * @param u U-value
	 * @param v V-value
	 * @since r461
	 */
	public final void setUV(final int polygonIndex, final int point, final float u, final float v)
	{
		final JGLPolygon polygon = getPolygon(polygonIndex);
		polygon.setUV(point, new UV(u, v));
	}
	private final void checkForLists()
	{
		//if there is a glList for the object, then recall it.
		if(this.glListIndex != JGLConstants.NULL_LIST && firstCall == false)
		{			
			//recall the list
			GL_INSTANCE.glCallList(this.glListIndex);
			//break from the method since its recalled the object
			return;
		}
	}
	private final void initiateRender()
	{
		//TODO: confirm this is not needed
		//enable rgb blending
		//GL_INSTANCE.glEnable(GL.GL_BLEND);		
		//enable alpha blending
		//GL_INSTANCE.glEnable(GL.GL_ALPHA_TEST);
		//check which alpha blending function to use
		if(additiveBlend)						
			GL_INSTANCE.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
		else
			GL_INSTANCE.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
		//do alpha blending
		//GL_INSTANCE.glAlphaFunc(GL.GL_GREATER, 0);		
	}
	private final void renderTexture(final JGLPolygon polygon)
	{
		if(polygon.getTexture() != null)
			polygon.texture.bind();
		else
		{	
			//bind a blank texture
			if(JGLTextureLoader.BLANK == null)			
				JGLTextureLoader.BLANK = JGLTextureLoader.loadIMG(null, false, null);
			JGLTextureLoader.BLANK.bind();
		}	
	}
	private final void cleanLists()
	{
		//determine if the list already exists
		if(this.glListIndex != JGLConstants.NULL_LIST)
		{
			//since the list already exists, delete it
			GL_INSTANCE.glDeleteLists(this.glListIndex, 1);		
		}
	}
	public JGLObject clone()
	{
		final JGLObject clone = new JGLObject();
		
		clone.additiveBlend = this.additiveBlend;
		for(JGLPolygon clonePolygon: this.polygons)
			clone.addPolygon(clonePolygon.clone());
		clone.glListIndex = this.glListIndex;
		clone.firstCall = this.firstCall;
		
		return clone;
	}
}
